//
//  HACTecCalculator.m
//  HStockCharts
//
//  Created by Hotacool on 2018/9/30.
//

#import "HACTecCalculator.h"
#import "HACKLineEntry.h"
#import "HACTimeLineEntry.h"

static const CGFloat FLOAT_ZERO_ERROR = 0.00000001; //浮点0值误差
static const CGFloat PRICE_ZERO_ERROR = 0.00000001; //浮点0价格

@implementation HACTecCalculator

+(NSArray<HACTecMACDEntry *> *)calculateMACDWithData:(NSArray *)data
                                                ema1:(NSInteger)ema1
                                                ema2:(NSInteger)ema2
                                                 dea:(NSInteger)dea {
    NSMutableArray *result;
    if (data && data.count > 0) {
        result  = [NSMutableArray arrayWithCapacity:data.count];
        long maxcount = data.count;
        double macd[maxcount];
        double emaline[2][maxcount];
        double temp = [self realValue:data[0]];
        emaline[0][0] = emaline[1][0] = temp;
        for (int i = 1; i < maxcount; i++) {
            temp = [self realValue:data[i]];
            emaline[0][i] = (temp*2+emaline[0][i-1]*(ema1-1))/(ema1+1);
            emaline[1][i] = (temp*2+emaline[1][i-1]*(ema2-1))/(ema2+1);
        }
        // DIF = EMA(12) - EMA(26)
        for (int i = 0; i < maxcount; i++) {
            emaline[0][i] -= emaline[1][i];
        }
        //　DEA（MACD）
        emaline[1][0] = emaline[0][0];
        for (int i = 1; i < maxcount; i++) {
            emaline[1][i] = (double)(emaline[0][i]*2+emaline[1][i-1]*(dea-1))/(dea+1);
        }
        // BAR
        for (int i = 0 ;i < maxcount ; i++){
            macd[i] = 2*(emaline[0][i] - emaline[1][i]);
        }
        // boxing
        for (int i = 0; i < maxcount; i++) {
            HACTecMACDEntry *macdValue = [[HACTecMACDEntry alloc] init];
            macdValue.dDIF = emaline[0][i];
            macdValue.dDEA = emaline[1][i];
            macdValue.dMacd = macd[i];
            [result addObject:macdValue];
        }
    }
    return result;
}

+(NSArray<HACTecKDJEntry *> *)calculateKDJWithData:(NSArray *)data N:(NSInteger)N M1:(NSInteger)M1 M2:(NSInteger)M2
{
    NSMutableArray *result;
    if (data && data.count > 0) {
        NSMutableArray *rsv = [NSMutableArray arrayWithCapacity:data.count];
        for (int i = 0; i < data.count; i++) {
            HACChartDataEntry *kitem = data[i];
            double min = [self realMinValue:kitem], max = [self realMaxValue:kitem];
            for (int j = i; j > i - N && j >= 0; j--) {
                HACChartDataEntry *obj = data[j];
                max = MAX([self realMaxValue:obj], max);
                min = MIN([self realMinValue:obj], min);
            }
            if (min == max) {
                [rsv addObject:@0];
            } else {
                [rsv addObject:@(([self realValue:kitem] - min)/(max - min)*100)];
            }
        }
        
        NSArray <NSNumber*>*k = _SMA(N, 1, rsv);
        NSArray<NSNumber *> *fixK = k.count > M1 - 1 ? [k subarrayWithRange:NSMakeRange(M1 - 1, k.count - M1 + 1)] : @[];
        NSMutableArray <NSNumber*>*d = [NSMutableArray arrayWithArray:_SMA(M1, 1, fixK)];
        for (int i = 0; i < M1 - 1; i++) {
            [d insertObject:@0 atIndex:0];
        }
        result = [NSMutableArray arrayWithCapacity:k.count];
        for (int l = 0; l < k.count; l++) {
            HACTecKDJEntry *kdj = [[HACTecKDJEntry alloc] init];
            kdj.K = l < M1 - 1 ? 0 : k[l].doubleValue;
            kdj.D = l < M2 - 1 ? 0 : d[l].doubleValue;
            kdj.J = l < MAX(M1, M2) - 1 ? 0 : 3*kdj.K - 2*kdj.D;
            [result addObject:kdj];
        }
    }
    return result;
}

+(NSArray<HACTecKDJEntry *> *)calculateRSIWithData:(NSArray *)data N1:(NSInteger)N1 N2:(NSInteger)N2 N3:(NSInteger)N3 {
    NSMutableArray *result;
    if (data && data.count > 0) {
        //1. 恒生rsi算法
        result = [NSMutableArray arrayWithCapacity:data.count];
        double rsi[3][2] = {0};//rsi1、rsi2、rsi3涨跌和 //0涨1跌
        for (NSUInteger i = 0; i < data.count; i++) {
            id klineData = data[i];
            HACTecRSIEntry *r = [HACTecRSIEntry new];
            [result addObject:r];
            if (i == 0) {
                //rsi基本值初始化
                rsi[0][0] = rsi[1][0] = rsi[2][0] = rsi[0][1] = rsi[1][1] = rsi[2][1] = 0;
                r.dRSI1 = r.dRSI2 = r.dRSI3 = 50;
            } else {
                //rsi各项指标(0-100)
                NSInteger j;
                for (j = 0; j < 3; j++) {
                    NSInteger limit = 0;
                    switch (j) {
                        case 0:
                            limit = N1;
                            break;
                        case 1:
                            limit = N2;
                            break;
                        case 2:
                            limit = N3;
                            break;
                        default:
                            break;
                    }
                    double closePrice = [self realValue:klineData];
                    double preClosePrice = [self realValue:data[i-1]];
                    if (closePrice > preClosePrice) {
                        rsi[j][0] = (closePrice - preClosePrice  + rsi[j][0] * (limit - 1.0)) / limit;
                        rsi[j][1] = (closePrice - preClosePrice + rsi[j][1] * (limit - 1.0)) / limit;;
                    }
                    else {
                        rsi[j][0] = rsi[j][0] * (limit - 1.0) / limit;
                        rsi[j][1] = (preClosePrice - closePrice + rsi[j][1] * (limit - 1.0)) / limit;
                    }
                    void(^assignBlk)(HACTecRSIEntry*, NSInteger, double) = ^(HACTecRSIEntry* rsi, NSInteger idx, double value) {
                        switch (idx) {
                            case 0:
                                rsi.dRSI1 = value;
                                break;
                            case 1:
                                rsi.dRSI2 = value;
                                break;
                            case 2:
                                rsi.dRSI3 = value;
                                break;
                        }
                    };
                    double value;
                    if (rsi[j][1] == 0) {
                        value = (rsi[j][0] == 0) ? 50 : 100;
                    } else {
                        value = rsi[j][0] / rsi[j][1] * 100;
                    }
                    assignBlk(r, j, value);
                }
            }
        }
        //2. RSI1:SMA(MAX(CLOSE-REF(C,1),0),N1,1)/SMA(ABS(CLOSE-REF(C,1)),N1,1)*100;
        /**
        NSMutableArray<NSNumber*> *closeMaxArray = [NSMutableArray arrayWithCapacity:data.count];
        NSMutableArray<NSNumber*> *closeAbsArray = [NSMutableArray arrayWithCapacity:data.count];
        int lastClose = 0;
        for (id klineData in data) {
            if (lastClose > 0) {
                [closeMaxArray addObject:@(MAX([self realValue:klineData] - lastClose, 0))];
                [closeAbsArray addObject:@(ABS([self realValue:klineData] - lastClose))];
            } else {
                [closeMaxArray addObject:@0];
            }
            lastClose = [self realValue:klineData];
        }
        NSMutableArray<NSNumber *> *tmpArray;
        NSArray<NSNumber *> *smaMaxArray = _SMA(N1, 1, closeMaxArray);
        tmpArray = [NSMutableArray arrayWithArray:_SMA(N1, 1, closeAbsArray)];
        [tmpArray insertObject:@0 atIndex:0];
        NSArray<NSNumber *> *smaAbsArray = tmpArray.copy;
        NSArray<NSNumber *> *smaMaxArray2 = _SMA(N2, 1, closeMaxArray);
        tmpArray = [NSMutableArray arrayWithArray:_SMA(N2, 1, closeAbsArray)];
        [tmpArray insertObject:@0 atIndex:0];
        NSArray<NSNumber *> *smaAbsArray2 = tmpArray.copy;
        NSArray<NSNumber *> *smaMaxArray3 = _SMA(N3, 1, closeMaxArray);
        tmpArray = [NSMutableArray arrayWithArray:_SMA(N3, 1, closeAbsArray)];
        [tmpArray insertObject:@0 atIndex:0];
        NSArray<NSNumber *> *smaAbsArray3 = tmpArray.copy;

        result = [NSMutableArray arrayWithCapacity:data.count];
        for (NSInteger i = 0; i < smaMaxArray.count; i++) {
            HACTecRSIEntry *rsi = [HACTecRSIEntry new];
            if (i < N1 - 1 || [smaAbsArray[i] isEqualToNumber:@0]) {
                rsi.dRSI1 = 0;
            } else {
                rsi.dRSI1 = smaMaxArray[i].doubleValue / smaAbsArray[i].doubleValue * 100;
            }
            if (i < N2 - 1 || [smaAbsArray2[i] isEqualToNumber:@0]) {
                rsi.dRSI2 = 0;
            } else {
                rsi.dRSI2 = smaMaxArray2[i].doubleValue / smaAbsArray2[i].doubleValue * 100;
            }
            if (i < N3 - 1 || [smaAbsArray3[i] isEqualToNumber:@0]) {
                rsi.dRSI3 = 0;
            } else {
                rsi.dRSI3 = smaMaxArray3[i].doubleValue / smaAbsArray3[i].doubleValue * 100;
            }
            [result addObject:rsi];
        }
        */
    }
    return result;
}

+ (NSArray<HACTecBOLLEntry *> *)calculateBOLLWithData:(NSArray<HACKLineEntry *> *)data MA:(NSInteger)ma W:(NSInteger)w {
    NSMutableArray *result;
    if (data.count > 0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        double __block bollmaSum = 0;//BOLL相关
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            double lastClose = [self realValue:klineData];
            HACTecBOLLEntry *item = [HACTecBOLLEntry new];
            if (idx == 0) {
                //boll基本值初始化
                bollmaSum  =  lastClose;
                item.MB = lastClose;
                item.UP = lastClose;
                item.DN = lastClose;
            } else {
                //BOLL，有意义实体线
                double bollMS = 0, bollMD = 0;
                if (idx < ma) {
                    bollmaSum += [self realValue:klineData];
                    item.MB = bollmaSum / (idx+1);
                    bollMS = 0;
                    for (int j = 0; j < idx; j++) {
                        HACKLineEntry *jitem = data[j];
                        bollMS += pow([self realValue:jitem] - item.MB, 2);
                    }
                    bollMD = sqrt(bollMS / idx);
                    item.UP = item.MB + w * bollMD;
                    item.DN = item.MB - w * bollMD;
                } else {
                    HACKLineEntry *jitem = data[idx-ma];
                    bollmaSum += lastClose - [self realValue:jitem];
                    item.MB = bollmaSum / ma;
                    bollMS = 0;
                    for (NSInteger j = idx - ma; j < idx; j++) {
                        jitem = data[j];
                        bollMS += pow([self realValue:jitem] - item.MB, 2);
                    }
                    bollMD = sqrt(bollMS / ma);
                    item.UP = item.MB + (double)w * bollMD;
                    item.DN = item.MB - (double)w * bollMD;
                }
            }
            [result addObject:item];
        }];
    }
    return result;
}

+(NSArray<HACTecPSYEntry *> *)calculatePSYWithData:(NSArray<HACKLineEntry*> *)data N:(NSInteger)N M:(NSInteger)M{
    NSMutableArray *result;
    if (data.count > 0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        int __block psySum = 0;//PSY相关
        double __block psymaSum = 0;
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            float lastClose = klineData.closePrice;
            HACTecPSYEntry *item = [HACTecPSYEntry new];
            if (idx == 0) {
                psySum = 0;
                psymaSum = 0;
                item.PSY = 0;
                item.PSYMA = 0;
            } else {
                //PSY指标（0－100）
                if (idx < N+1) {
                    if (lastClose > ((HACKLineEntry *)data[idx-1]).closePrice) {
                        psySum++;
                    }
                    item.PSY = 100.0 * psySum / (float)(idx+1);
                }else{
                    if (lastClose > ((HACKLineEntry *)data[idx-1]).closePrice) {
                        psySum ++;
                    }
                    if ((idx >= (N+1)) && ((HACKLineEntry *)data[idx-N]).closePrice > ((HACKLineEntry *)data[idx-N-1]).closePrice) {
                        psySum --;
                    }
                    item.PSY = 100.0 * psySum / N;
                    
                }
                if (idx < M) {
                    psymaSum += item.PSY;
                    item.PSYMA = psymaSum / (idx+1);
                }else{
                    psymaSum += item.PSY - ((HACTecPSYEntry *)result[idx-M]).PSY;
                    item.PSYMA = psymaSum / M;
                }
            }
            [result addObject:item];
        }];
    }
    return result;
}

+(NSArray<HACTecOBVEntry *> *)calculateOBVWithData:(NSArray<HACKLineEntry*> *)data M:(NSInteger)M{
    NSMutableArray *result;
    if (data.count > 0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        double __block maSum = 0;
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            float lastClose = klineData.closePrice;
            HACTecOBVEntry *item = [HACTecOBVEntry new];
            if (idx == 0) {
                //obv基本值初始化
                item.OBV = klineData.volume;//基期成交量
                maSum = 0;
            } else {
                //OBV
                if(lastClose > ((HACKLineEntry *)data[idx-1]).closePrice){
                    item.OBV = ((HACTecOBVEntry *)result[idx-1]).OBV + klineData.volume;
                }
                else if(lastClose < ((HACKLineEntry *)data[idx-1]).closePrice){
                    item.OBV = ((HACTecOBVEntry *)result[idx-1]).OBV - klineData.volume;
                }else{
                    item.OBV = ((HACTecOBVEntry *)result[idx-1]).OBV;
                }
                
                if (idx < M) {
                    maSum += item.OBV;
                    item.OBVMA = maSum / (idx+1);
                }else{
                    maSum += item.OBV - ((HACTecOBVEntry *)result[idx-M]).OBV;
                    item.OBVMA = maSum / M;
                }
            }
            [result addObject:item];
        }];
    }
    return result;
}

+(NSArray<HACTecDMIEntry *> *)calculateDMIWithData:(NSArray<HACKLineEntry*> *)data N:(NSInteger)N M:(NSInteger)M{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:data.count];
        double __block dmiUpDMSum = 0,dmiDownDMSum = 0,dmiTRSum = 0,dmiDXSum = 0;//DMI相关
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecDMIEntry *item = [HACTecDMIEntry new];
            HACTecDMIDIEntry *diItem = [HACTecDMIDIEntry new];
            if (idx == 0) {
                //dmi基本值初始化
                dmiUpDMSum = dmiDownDMSum = dmiTRSum = 0;
                dmiDXSum = 0;
                item.PDI = 0;
                item.MDI = 0;
                item.ADX = 0;
                item.ADXR =0;
            }else{
                HACKLineEntry *preKlineData = (HACKLineEntry *)data[idx-1];
                diItem.UPDM = klineData.maxPrice - preKlineData.maxPrice;
                if (diItem.UPDM<0) {
                    diItem.UPDM = 0;
                }
                diItem.DOWNDM = preKlineData.minPrice - klineData.minPrice;
                if (diItem.DOWNDM<0) {
                    diItem.DOWNDM = 0;
                }
                if (diItem.UPDM>diItem.DOWNDM) {
                    diItem.DOWNDM = 0;
                }
                else if (diItem.UPDM<diItem.DOWNDM) {
                    diItem.UPDM = 0;
                }
                else{
                    diItem.UPDM = diItem.DOWNDM =0;
                }
                if (idx<N) {
                    dmiUpDMSum += diItem.UPDM;
                }
                else{
                    dmiUpDMSum += diItem.UPDM - ((HACTecDMIDIEntry *)tempArray[idx-N]).UPDM;
                }
                if (idx<N) {
                    dmiDownDMSum += diItem.DOWNDM;
                }
                else{
                    dmiDownDMSum +=diItem.DOWNDM - ((HACTecDMIDIEntry *)tempArray[idx-N]).DOWNDM;
                }
                diItem.TR = MAX(MAX(fabsf(klineData.maxPrice - klineData.minPrice),
                                    fabsf(klineData.maxPrice - preKlineData.closePrice)),
                                fabsf(klineData.minPrice - preKlineData.closePrice));
                if (idx<N) {
                    dmiTRSum += diItem.TR;
                }
                else{
                    dmiTRSum +=diItem.TR - ((HACTecDMIDIEntry *)tempArray[idx-N]).TR;
                }
                if (dmiTRSum != 0) {
                    item.PDI = dmiUpDMSum/dmiTRSum*100;
                    item.MDI = dmiDownDMSum/dmiTRSum*100;
                }else{
                    item.PDI = 0;
                    item.MDI = 0;
                }
                if ((item.PDI + item.MDI) != 0) {
                    diItem.DX = fabs(item.PDI - item.MDI)/(item.PDI + item.MDI)*100;
                }else{
                    diItem.DX = 0;
                }
                if (idx < M) {
                    dmiDXSum += diItem.DX;
                    item.ADX = dmiDXSum/(idx+1);
                }
                else{
                    dmiDXSum +=diItem.DX - ((HACTecDMIDIEntry *)tempArray[idx-M]).DX;
                    item.ADX = dmiDXSum/M;
                }
                if (idx<M) {
                    item.ADXR = (item.ADX + ((HACTecDMIEntry *)result[idx-1]).ADX)/2;
                }else{
                    item.ADXR = (item.ADX + ((HACTecDMIEntry *)result[idx-M]).ADX)/2;
                }
            }
            [result addObject:item];
            [tempArray addObject:diItem];
        }];
    }
     return result;
}

+(NSArray<HACTecWREntry *> *)calculateWRWithData:(NSArray<HACKLineEntry*> *)data ema1:(NSInteger)ema1 ema2:(NSInteger)ema2{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        long __block highPrice = 0, lowPrice = 0;//wr相关
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecWREntry *item = [HACTecWREntry new];
            if (idx == 0) {
                //wr、kdj基本值初始化
                if (klineData.maxPrice == klineData.minPrice) {
                    item.W_R = 100;
                }
                else
                {
                    item.W_R = 100.0*(klineData.maxPrice - klineData.closePrice)/(klineData.maxPrice - klineData.minPrice);
                }
            }else{
                //wr指标(0-100)
                //WR1一般是6天买卖强弱指标；
                //WR2一般是10天买卖强弱指标
                NSInteger j = 0;
                j = idx > (ema1 - 1) ? (idx-ema1+1) : 0;
                lowPrice = highPrice = 0;
                for ( ; j <=idx; j++) {
                    HACKLineEntry *kLineItem = (HACKLineEntry *)[data objectAtIndex:j];
                    if (kLineItem.maxPrice > highPrice || highPrice == 0 ) {
                        highPrice = kLineItem.maxPrice;
                    }
                    if ((kLineItem.minPrice < lowPrice || lowPrice == 0) && kLineItem.minPrice != 0) {
                        lowPrice = kLineItem.minPrice;
                    }
                }
                if (highPrice - lowPrice > 0) {
                    item.W_R = 100.0*(highPrice - klineData.closePrice)/(highPrice-lowPrice);
                }
                else //  连续停牌
                {
                    item.W_R = 100.0;
                }
                
                j = idx > (ema2 - 1) ? (idx-ema2+1) : 0;
                lowPrice = highPrice = 0;
                for ( ; j <=idx; j++) {
                    HACKLineEntry *kLineItem = (HACKLineEntry *)[data objectAtIndex:j];
                    if (kLineItem.maxPrice > highPrice || highPrice == 0 ) {
                        highPrice = kLineItem.maxPrice;
                    }
                    if ((kLineItem.minPrice < lowPrice || lowPrice == 0) && kLineItem.minPrice != 0) {
                        lowPrice = kLineItem.minPrice;
                    }
                }
                if (highPrice - lowPrice > 0) {
                    item.W_R2 = 100.0*(highPrice - klineData.closePrice)/(highPrice-lowPrice);
                }
                else //  连续停牌
                {
                    item.W_R2 = 100.0;
                }
            }
            [result addObject:item];
        }];
    }
     return result;
}

+(NSArray<HACTecASIEntry *> *)calculateASIWithData:(NSArray<HACKLineEntry*> *)data  M:(NSInteger)M{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        double __block asiA = 0, asiB = 0, asiC = 0, asiD = 0, asiE = 0, asiF = 0, asiG = 0, asiX = 0, asiR = 0, asiK = 0, asiSI = 0, asimaSum = 0;;//ASI
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecASIEntry *item = [HACTecASIEntry new];
            if (idx == 0) {
                //ASI
                item.ASI = 0;
                item.ASIMA = 0;
                asimaSum = 0;
            } else{
                HACKLineEntry *preKlineData = (HACKLineEntry *)data[idx-1];
                asiA = fabsf(klineData.maxPrice - preKlineData.closePrice);
                asiB = fabsf(klineData.minPrice - preKlineData.closePrice);
                asiC = fabsf(klineData.maxPrice - preKlineData.minPrice);
                asiD = fabsf(preKlineData.closePrice - preKlineData.openPrice);
                if (asiA > asiB && asiA > asiC) {
                    asiR = asiA + asiB / 2 + asiD / 4;
                }
                else if (asiB > asiA && asiB > asiC)
                {
                    asiR = asiB + asiA / 2 + asiD / 4;
                }
                else
                {
                    asiR = asiC + asiD / 4;
                }
                asiE = klineData.closePrice - preKlineData.closePrice;
                asiF = klineData.closePrice - klineData.openPrice;
                asiG = preKlineData.closePrice - preKlineData.openPrice;
                asiX = asiE + asiF / 2 + asiG;
                asiK = asiA > asiB ? asiA : asiB;
                if (asiR == 0) {
                    asiSI = 0.0160 * asiK;
                }
                else
                {
                    asiSI = 0.0160 * asiX / asiR * asiK ;
                }
                item.ASI = ((HACTecASIEntry *)result[idx-1]).ASI + asiSI;
                
                
                if (idx < M) {
                    asimaSum += item.ASI;
                    item.ASIMA = asimaSum / idx;
                    
                }
                else
                {
                    asimaSum += item.ASI - ((HACTecASIEntry *)result[idx - M]).ASI;
                    item.ASIMA = asimaSum / M;
                }
            }
            [result addObject:item];
        }];
    }
    return result;
}

+ (NSArray<HACTecDMAEntry*>*)calculateDMAWithData:(NSArray<HACKLineEntry * >*)data ema1:(NSInteger)ema1 ema2:(NSInteger)ema2 dea:(NSInteger)dea{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        double __block dmaShortmaSum = 0,dmaLongmaSum = 0,dmaDDDmaSum = 0,dmaShortma = 0,dmaLongma = 0;//DMA相关
        [data enumerateObjectsUsingBlock:^(HACKLineEntry  *_Nonnull kLineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecDMAEntry *item = [HACTecDMAEntry new];
            if (idx == 0) {
                //dma基本值初始化
                dmaShortmaSum = dmaLongmaSum  =  kLineData.closePrice/1000.0;
                dmaDDDmaSum = 0;
                item.DDD = 0;
                item.AMA = 0;
            }else{
                //DMA
                if (idx < ema1) {
                    dmaShortmaSum += kLineData.closePrice/1000.0;
                    dmaShortma = dmaShortmaSum / (idx+1);
                }
                else{
                    dmaShortmaSum += kLineData.closePrice/1000.0 - ((HACKLineEntry *)data[idx-ema1]).closePrice/1000.0;
                    dmaShortma = dmaShortmaSum / ema1;
                }
                if (idx < ema2) {
                    dmaLongmaSum += kLineData.closePrice/1000.0;
                    dmaLongma = dmaLongmaSum / (idx+1);
                }
                else{
                    dmaLongmaSum += kLineData.closePrice/1000.0 - ((HACKLineEntry *)data[idx-ema2]).closePrice/1000.0;
                    dmaLongma = dmaLongmaSum / ema2;
                }
                item.DDD = dmaShortma - dmaLongma;
                if (idx < dea) {
                    dmaDDDmaSum += item.DDD;
                    item.AMA = dmaDDDmaSum / (idx+1);
                }
                else{
                    dmaDDDmaSum += item.DDD - ((HACTecDMAEntry *)result[idx-dea]).DDD;
                    item.AMA = dmaDDDmaSum / ema1;
                }
            }
            [result addObject:item];
        }];
    }
     return result;
}

+(NSArray<HACTecBIASEntry *> *)calculateBIASWithData:(NSArray<HACKLineEntry*> *)data N1:(NSInteger)N1 N2:(NSInteger)N2 N3:(NSInteger)N3{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        double __block bias1maSum = 0, bias2maSum = 0, bias3maSum = 0; //bias相关
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecBIASEntry *item = [HACTecBIASEntry new];
            if (idx == 0) {
                //bias基本值初始化
                bias1maSum = bias2maSum = bias3maSum = klineData.closePrice;
                item.BIAS_0 = item.BIAS_1 = item.BIAS_2 = 0;
            }else{
                double maValue;
                if (idx < N1) {
                    bias1maSum += klineData.closePrice;
                    maValue = bias1maSum / idx;
                }
                else
                {
                    bias1maSum += klineData.closePrice - ((HACKLineEntry *)data[idx-N1]).closePrice;
                    maValue = bias1maSum / N1;
                }
                if (maValue < FLOAT_ZERO_ERROR && maValue > -FLOAT_ZERO_ERROR) {
                    maValue = PRICE_ZERO_ERROR;
                }
                item.BIAS_0 = (klineData.closePrice - maValue) / maValue * 100.0;
                if (idx < N2) {
                    bias2maSum += klineData.closePrice;
                    maValue = bias2maSum / idx;
                    
                }
                else
                {
                    bias2maSum += klineData.closePrice - ((HACKLineEntry *)data[idx-N2]).closePrice;
                    maValue = bias2maSum / N2;
                }
                if (maValue < FLOAT_ZERO_ERROR && maValue > -FLOAT_ZERO_ERROR) {
                    maValue = PRICE_ZERO_ERROR;
                }
                item.BIAS_1 = (klineData.closePrice - maValue) / maValue * 100.0;
                if (idx < N3) {
                    bias3maSum += klineData.closePrice;
                    maValue = bias3maSum / idx;
                    
                }
                else
                {
                    bias3maSum += klineData.closePrice - ((HACKLineEntry *)data[idx-N3]).closePrice;
                    maValue = bias3maSum / N3;
                }
                if (maValue < FLOAT_ZERO_ERROR && maValue > -FLOAT_ZERO_ERROR) {
                    maValue = PRICE_ZERO_ERROR;
                }
                item.BIAS_2 = (klineData.closePrice - maValue) / maValue * 100.0;
            }
            [result addObject:item];
        }];
    }
    return result;
}

+(NSArray<HACTecVREntry *> *)calculateVRWithData:(NSArray<HACKLineEntry*> *)data N:(NSInteger)N{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        double __block vrAVS = 0, vrBVS = 0, vrCVS = 0;
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecVREntry *item = [HACTecVREntry new];
            if (idx == 0) {
                vrAVS = 0;
                vrBVS = 0;
                vrCVS = klineData.volume;
            }else{
                if (klineData.closePrice > ((HACKLineEntry *)data[idx-1]).closePrice) {
                    vrAVS += klineData.volume;
                }
                else if (klineData.closePrice < ((HACKLineEntry *)data[idx-1]).closePrice) {
                    vrBVS += klineData.volume;
                }
                else {
                    vrCVS += klineData.volume;
                }
                
                if (idx == N) {
                    HACKLineEntry *itemVRPARAM = (HACKLineEntry *)data[idx-N];
                    vrCVS += itemVRPARAM.volume;
                }
                else if (idx > N)
                {
                    HACKLineEntry *itemVRPARAM = (HACKLineEntry *)data[idx-N];
                    HACKLineEntry *prevItemVRPARAM = (HACKLineEntry *)data[idx-N-1];
                    if (itemVRPARAM.closePrice > prevItemVRPARAM.closePrice) {
                        vrAVS -= itemVRPARAM.volume;
                    }
                    else if (itemVRPARAM.closePrice < prevItemVRPARAM.closePrice) {
                        vrBVS -= itemVRPARAM.volume;
                    }
                    else {
                        vrCVS -= itemVRPARAM.volume;
                    }
                }
                if (vrBVS + vrCVS / 2 < FLOAT_ZERO_ERROR && vrBVS + vrCVS / 2 > -FLOAT_ZERO_ERROR) {
                    item.VR = 100.0;
                }
                else
                {
                    item.VR = (vrAVS + vrCVS / 2) / (vrBVS + vrCVS / 2) * 100.0;
                }
            }
            [result addObject:item];
        }];
    }
    return result;
}

+(NSArray<HACTecCCIEntry *> *)calculateCCIWithData:(NSArray<HACKLineEntry*> *)data N:(NSInteger)N{
    NSMutableArray *result;
    if (data.count>0) {
        result = [NSMutableArray arrayWithCapacity:data.count];
        NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:data.count];
        double __block TPSum = 0,TPma = 0,BIASSum = 0,BIASMa = 0;//CCI相关
        [data enumerateObjectsUsingBlock:^(HACKLineEntry * _Nonnull klineData, NSUInteger idx, BOOL * _Nonnull stop) {
            HACTecCCIEntry *item = [HACTecCCIEntry new];
            HACTecCCITempEntry *tempItem = [HACTecCCITempEntry new];
            if (idx == 0) {
                //CCI基本值初始化
                BIASSum = TPSum = item.CCI = 0;
            }else{
                if (idx < N) {
                    tempItem.TP = (klineData.maxPrice + klineData.minPrice + klineData.closePrice)/3000.0;
                    TPSum += tempItem.TP;
                    TPma = TPSum / (idx+1);
                    tempItem.MD = tempItem.TP - TPma;
                    tempItem.BIAS = fabs(tempItem.TP - TPma);
                    BIASSum += tempItem.BIAS;
                    BIASMa = 0.015 * BIASSum / (idx+1);
                    item.CCI = (tempItem.TP - TPma) / BIASMa;
                }
                else{
                    tempItem.TP = (klineData.maxPrice +klineData.minPrice + klineData.closePrice)/3000.0;
                    TPSum += tempItem.TP - ((HACTecCCITempEntry *)tempArray[idx-N]).TP;
                    TPma = TPSum / N;
                    tempItem.MD = tempItem.TP - TPma;
                    tempItem.BIAS = fabs(tempItem.TP - TPma);
                    BIASSum += tempItem.BIAS - ((HACTecCCITempEntry *)tempArray[idx-N]).BIAS;
                    BIASMa = 0.015 * BIASSum / N;
                    item.CCI = (tempItem.TP - TPma) / BIASMa;
                }
            }
            [tempArray addObject:tempItem];
            [result addObject:item];
        }];
    }
    return result;
}


+ (double)realValue:(HACChartDataEntry*)data {
    if ([data isKindOfClass:[HACKLineEntry class]]) {
        return ((HACKLineEntry*)data).closePrice;
    } else if ([data isKindOfClass:[HACTimeLineEntry class]]) {
        return ((HACTimeLineEntry*)data).newprice;
    }
    return  0.0;
}

+ (double)realMaxValue:(HACChartDataEntry*)data {
    if ([data isKindOfClass:[HACKLineEntry class]]) {
        return ((HACKLineEntry*)data).maxPrice;
    } else if ([data isKindOfClass:[HACTimeLineEntry class]]) {
        return ((HACTimeLineEntry*)data).newprice;
    }
    return  0.0;
}

+ (double)realMinValue:(HACChartDataEntry*)data {
    if ([data isKindOfClass:[HACKLineEntry class]]) {
        return ((HACKLineEntry*)data).minPrice;
    } else if ([data isKindOfClass:[HACTimeLineEntry class]]) {
        return ((HACTimeLineEntry*)data).newprice;
    }
    return  0.0;
}



/** 移动平均线 */
NSArray<NSNumber *> * _SMA(int day, int weight, NSArray<NSNumber *> *array) {
    NSMutableArray<NSNumber *> *retArray;
    if (array && array.count > 0) {
        retArray = [NSMutableArray arrayWithCapacity:array.count];
        [retArray addObject:array.firstObject];
        for (int i = 1; i < array.count; i++) {
            double temp = (weight * array[i].doubleValue + (day - weight) * retArray[i - 1].doubleValue) / (double)day;
            [retArray addObject:@(temp)];
        }
    }
    return retArray?:@[];
}
@end
